﻿// === Copyright 2008-2009 Jamie Macia et al. ===
// Module:      DamageRoll
// Created:     11/18/2008
// Author:      Jamie Macia
// Description: An extension of the DiceRoll specific to damage
// Revisions:
//      *jmacia 11/18/08 Issue 1: Created

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace JMacia.Gaming.d20.Core.Dice
{

    /// <summary>
    /// An extension of the DiceRoll class specific to damage.
    /// This class takes into account the fact that some damage is multiplied on a critical hit while some is not.
    /// </summary>
    public class DamageRoll : DiceRoll
    {
        #region Protected Members

        protected int _critMultiplier = 2;
        protected DiceRoll _staticDamage = new DiceRoll();

        #endregion

        #region Constructors

        /// <summary>
        /// Empty constructor
        /// </summary>
        public DamageRoll() : base() { }

        /// <summary>
        /// Constructs a DamageRoll (all multiplicable) from a properly formatted string
        /// </summary>
        /// <param name="rollDefinition">A string that defines the multipliable damage</param>
        public DamageRoll(string rollDefinition) : base(rollDefinition) { }

        /// <summary>
        /// Constructor that defines both multipliable and static damage from strings
        /// </summary>
        /// <param name="multipliableDmg">The damage that is multiplied on a critical hit</param>
        /// <param name="staticDmg">The damage that is not multiplied on a critical hit</param>
        /// <seealso cref="DiceRoll.Parse(string)"/>
        public DamageRoll(string multipliableDmg, string staticDmg)
            : base(multipliableDmg)
        {
            _staticDamage.Parse(staticDmg);
        }

        /// <summary>
        /// Constructs the damage roll from two DiceRolls
        /// </summary>
        /// <param name="multipliableDmg">The damage that is multiplied on a critical hit</param>
        /// <param name="staticDmg">The damage that is not multiplied on a critical hit</param>
        public DamageRoll(DiceRoll multipliableDmg, DiceRoll staticDmg)
            : base(multipliableDmg)
        {
            _staticDamage = new DiceRoll(staticDmg);
        }

        /// <summary>
        /// Allows user to specify a critical hit multiplier
        /// </summary>
        /// <param name="multipliableDmg">The damage that is multiplied on a critical hit</param>
        /// <param name="staticDmg">The damage that is not multiplied on a critical hit</param>
        /// <param name="critMultiplier">The number of times the multipliable damage is rolled on a critical hit</param>
        public DamageRoll(string multipliableDmg, string staticDmg, int critMultiplier)
            : base(multipliableDmg)
        {
            _staticDamage.Parse(staticDmg);
            _critMultiplier = critMultiplier;
        }

        /// <summary>
        /// Copy constructor
        /// </summary>
        /// <param name="copy">The DamageRoll of which to make a copy</param>
        public DamageRoll(DamageRoll copy)
            : base(copy)
        {
            this._critMultiplier = copy._critMultiplier;
            this._staticDamage = new DiceRoll(copy._staticDamage);
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Parses both the multipliable and static damage
        /// </summary>
        /// <param name="multipliableRollDefinition">The damage that is multiplied on a critical hit</param>
        /// <param name="staticRollDefinition">The damage that is not multiplied on a critical hit</param>
        public void Parse(string multipliableRollDefinition, string staticRollDefinition)
        {
            base.Parse(multipliableRollDefinition);
            _staticDamage.Parse(staticRollDefinition);
        }

        /// <summary>
        /// Parses the static damage only.
        /// </summary>
        /// <param name="staticRollDefinition">The damage that is not multiplied on a critical hit</param>
        public void ParseStatic(string staticRollDefinition)
        {
            _staticDamage.Parse(staticRollDefinition);
        }

        /// <summary>
        /// Rolls both the multipliable and the static damage.
        /// </summary>
        /// <param name="individualRolls">
        /// A list to be populated with the values of the individual rolls</param>
        /// <returns>The total value of the dice and the modifier</returns>
        /// <remarks cref="DiceRoll.Roll()">
        /// This will be called polymorphically by Roll()</remarks>
        public override int Roll(out List<int> individualRolls)
        {
            List<int> stat;
            int val = base.Roll(out individualRolls);
            val += _staticDamage.Roll(out stat);
            individualRolls.AddRange(stat);
            return val;
        }

        /// <summary>
        /// Adds dice to the static damage.
        /// </summary>
        /// <param name="numDice">Number of dice to be added</param>
        /// <param name="dieSides">Number of sides per die to be added</param>
        public void AddStaticDice(int numDice, int dieSides)
        {
            _staticDamage.AddDice(numDice, dieSides);
        }

        /// <summary>
        /// Adds sets of dice to the static damage roll
        /// </summary>
        /// <param name="sets">Sets of dice to be added</param>
        public void AddStaticDice(params DiceSet[] sets)
        {
            _staticDamage.AddDice(sets);
        }

        /// <summary>
        /// Rolls a critical hit
        /// </summary>
        /// <returns>The total damage</returns>
        public virtual int RollCritical()
        {
            int roll = _staticDamage.Roll();
            for (int i = 0; i < _critMultiplier; i++)
            {
                roll += base.Roll();
            }
            return roll;
        }

        /// <summary>
        /// Rolls a critical hit
        /// </summary>
        /// <param name="individualRolls">The individual damage dice</param>
        /// <returns>The total damage</returns>
        public virtual int RollCritical(out List<int> individualRolls)
        {
            List<int> statRolls;
            int roll = _staticDamage.Roll(out statRolls);
            individualRolls = new List<int>();
            for (int i = 0; i < _critMultiplier; i++)
            {
                List<int> rolls;
                roll += base.Roll(out rolls);
                individualRolls.AddRange(rolls);
            }
            individualRolls.AddRange(statRolls);
            return roll;
        }

        /// <summary>
        /// String representation of all the damage dice
        /// </summary>
        /// <returns>a string representation of the damage</returns>
        public override string ToString()
        {
            return string.Format("{0}+{1}", base.ToString(), _staticDamage);
        }

        /// <summary>
        /// An overload of the ToString method that allows you to specify what is included in the output
        /// </summary>
        /// <param name="type">
        /// A string representing the type of output desired.
        /// "M" indicates multipliable damage only,
        /// "S" indicates static damage only,
        /// "A" or anything else indicates all damage.
        /// It is case insensitive and discards all but the first character</param>
        /// <returns>The damage string requested</returns>
        public string ToString(string type)
        {
            if (type.Length == 0)
            {
                return ToString();
            }
            switch (type.ToUpper()[0])
            {
                case 'M':   // multipliable damage
                    return base.ToString();
                case 'S':   // static damage
                    return _staticDamage.ToString();
                case 'A':   // all damage
                default:    // unsupported, default to all
                    return ToString();
            }
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// The critical hit multiplier.  Multipliable damage is rolled this many times when rolling a critical hit.
        /// </summary>
        public int CritMultiplier
        {
            get
            {
                return _critMultiplier;
            }
            set
            {
                _critMultiplier = value;
            }
        }

        /// <summary>
        /// A string representation of the multipliable damage.  Used for XML serialization.
        /// </summary>
        public string SerialMultipliableDamage
        {
            get
            {
                return base.ToString();
            }
            set
            {
                Parse(value);
            }
        }

        /// <summary>
        /// A string representation of the static damage.  Used for XML serialization.
        /// </summary>
        public string SerialStaticDamage
        {
            get
            {
                return _staticDamage.ToString();
            }
            set
            {
                _staticDamage.Parse(value);
            }
        }

        #endregion
    }
}